package wassalt.client;

import java.io.IOException;
import java.util.List;
import java.util.Locale;

import wassalt.Services.GpsService;
import wassalt.Services.GpsService.LocalBinder;
import wassalt.Utils.AppConstants;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

/** * 
 * Activity to display Google Maps to the user to select a destination
 * 
 * @author Dalia
 * **/
public class Map extends MapActivity {
	
	protected String TAG = "Map";
	
	
	MapView mapView;
	MyLocationOverlay myLocationOverlay;
	
	//location coordinates
	double longitude=0, latitude=0;
	//corresponding address; if available
	String address=""; 
	
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map);
        
        mapView = (MapView) findViewById(R.id.mapview);
        //enable zooming
        mapView.setBuiltInZoomControls(true);
        //set initial zoom
        mapView.getController().setZoom(13);
                
        //go to default location if exists
        if (!getDefaultLocation()){ //else go to current if exists
        	getCurrentLocation();
        	if (latitude==-91 & longitude==-181)//else set initial point to Cairo
        		mapView.getController().setCenter(new GeoPoint(30058056, 31228889));
        	else
        		mapView.getController().setCenter(new GeoPoint((int)latitude*1000000,(int)longitude*1000000));
        }
        else
        	mapView.getController().setCenter(new GeoPoint((int)latitude*1000000,(int)longitude*1000000));
        	
        //add overlay to show user's location
        myLocationOverlay = new MyLocationOverlay(this, mapView);
        myLocationOverlay.enableMyLocation();
        
        //add overlay to allow getting point by tapping the screen
        MapOverlay overlay = new MapOverlay(); 
        mapView.getOverlays().clear();
        mapView.getOverlays().add(overlay); 
        
        
    }
	
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		  MenuInflater inflater = getMenuInflater();
		  inflater.inflate(R.menu.map_menu, menu);
		  return super.onCreateOptionsMenu(menu);
	}
	
	


	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
	    switch (item.getItemId()) {
	    case R.id.current_loc:
	        goTo(0);
	        return true;
	    case R.id.default_loc:
	    	goTo(1);
	    	return true;
	    case R.id.set_default_loc:
	    	setDefaultLocation();
	    	return true;
	    case R.id.custom_loc:
	    	goTo(2);
	    	return true;
	    default:
	        return super.onOptionsItemSelected(item);
	    }
		
	}
	
	/**
	 * Animates the map to either the user's current location or his default location
	 * @param current
	 */
	public void goTo(int i){
		switch (i){
		case 0:
			getCurrentLocation(); 
			break;
		case 1:
			if(!getDefaultLocation())
				Toast.makeText(getBaseContext(), getString(R.string.negative), Toast.LENGTH_SHORT);
			break;
		case 2:
			getCustomLocation();
			break;
		}
		mapView.getController().animateTo(new GeoPoint((int)latitude*1000000,(int)longitude*1000000));
		//mapView.getController().zoomIn();
		//mapView.getController().setZoom(18);
		
	}
	
	/**
	 * Prompts user to enter an address.
	 * @author Dalia
	 */
	public void getCustomLocation(){
		final Dialog d = new Dialog(mapView.getContext());
		d.setContentView(R.layout.input_address);
		d.setTitle(getString(R.string.custom_loc));
		d.setCancelable(true);
		Button b = (Button)d.findViewById(R.id.go);
		b.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				EditText txt = (EditText) d.findViewById(R.id.addr);
				String addr = txt.getText().toString();
				GeoPoint p = getGeoPoint(addr);
				if(p.getLatitudeE6()/1000000.0==-91 &
							p.getLongitudeE6()/1000000.0==-181){
						Toast.makeText(mapView.getContext(), getString(R.string.search_failed), Toast.LENGTH_SHORT);
				}
				else{
					latitude = p.getLatitudeE6()/1000000.0;
					longitude = p.getLongitudeE6()/1000000.0;
					
				}
				d.dismiss();
			}
		});
		Button c = (Button)d.findViewById(R.id.cancel);
		c.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				d.dismiss();
			}
		});
		d.show();
	}
	/**
	 * Retreives the user's last known location if available.
	 * @author Dalia
	 * 
	 * **/
	
	public void getCurrentLocation(){
		//Intent i = new Intent(this, GpsService.class);
		/*new ServiceConnection(){
			@Override
            public void onServiceConnected(ComponentName className, IBinder service) {   
                GpsService s = ((LocalBinder) service).getService();
                double [] loc=s.getCurrentLocation();
                if (loc[0]!=-1 && loc[1]!=-1){
                	latitude=loc[0];
                	longitude=loc[1];
                	
                }
                            
            }
            @Override
            public void onServiceDisconnected(ComponentName className) {


            }
        };
        */
		double [] loc = GpsService.getCurrentLocation();
		latitude = loc[0];
		longitude = loc[1];
		
		/*GeoPoint p =myLocationOverlay.getMyLocation();
		if(p!=null){
			latitude = p.getLatitudeE6()/1000000;
			longitude = p.getLongitudeE6()/1000000;
		}
		*/
		//mapView.getOverlays().add(myLocationOverlay);
		//mapView.getOverlays().remove(1);
		
		/*LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);

		Location lastLoc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
		if(lastLoc!=null){
			mapView.getController().setCenter(new GeoPoint((int)lastLoc.getLatitude()*1000000,
					(int)lastLoc.getLongitude()*1000000));
		}*/
		
	}
	/**
	 * Retrieves the user's default location
	 * @return success if location has been found
	 * @author Dalia
	 */
	public boolean getDefaultLocation(){
		SharedPreferences s = getApplicationContext().getSharedPreferences
		(AppConstants.SHARED_PREFS, Context.MODE_WORLD_READABLE);
		String loc = s.getString(AppConstants.DEFAULT_LOC, "");
		if (loc!=""){
			String [] l = loc.split(",");
			latitude = Double.parseDouble(l[0]);
			longitude = Double.parseDouble(l[1]);
			return true;
		}
		else{
			return false;
		}
	}
	/**
	 * Get the current latitude and longitude
	 * @return
	 */
	public double[] getLatLong(){
		return new double[] {latitude,longitude};
	}
	/**
	 * Retrieves the current center of the map
	 * @author Dalia
	 */
	public void getCurrentViewPoint(){
		GeoPoint p =mapView.getMapCenter();
		latitude = p.getLatitudeE6()/1000000.0;
		longitude = p.getLongitudeE6()/1000000.0;
	}
	
	/**
	 * Adds or edits the user's default location
	 * @author Dalia
	 */
	public void setDefaultLocation(){
		getCurrentViewPoint();
		String loc=getAddress();
	 
	
	try{
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		String a = 	getString(R.string.confirm_def);
		String la = getString(R.string.lat);
		String lo = getString(R.string.longi);
		String msg = "";
		//for reordering text from right to left in case of arabic
		if (Locale.getDefault().getLanguage().equals("ar"))
			msg= a+"\n"+loc+"\n"+latitude+la+"\n"+longitude+lo;
		else
			msg= a+"\n"+loc+"\n"+la+latitude+"\n"+lo+longitude;
		builder.setMessage(msg)
		.setCancelable(true)
		.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int id) {
				SharedPreferences s = getApplicationContext().getSharedPreferences
				(AppConstants.SHARED_PREFS, Context.MODE_APPEND);
				SharedPreferences.Editor editor = s.edit();
				editor.putString(AppConstants.DEFAULT_LOC, latitude+","+longitude);
				editor.commit();
				Toast.makeText(getApplicationContext(), getString(R.string.def_done), Toast.LENGTH_SHORT);
			}
		})
		.setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int id) {
				dialog.cancel();
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	 }
	 catch (Exception e){
		 e.printStackTrace();
		 Log.e(TAG, "Confirmation Dialog problem");
	 }
	}
	
	/**
	 * @author Dalia
	 * 
	 * Called after the user has chosen a location.
	 * It goes back to the original activity with the 
	 * user's chosen location.
	 * ***/
	public void onResult(){
		Intent i = new Intent();
		i.putExtra("longitude",longitude);
		i.putExtra("latitude",latitude);
		i.putExtra("address", address);
		setResult(Activity.RESULT_OK, i);
		finish();
			
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		
		super.onDestroy();
		myLocationOverlay.disableMyLocation(); //stop getting updates
	}

	@Override
	protected void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		myLocationOverlay.disableMyLocation(); //stop getting updates
	}
	

	@Override
	protected void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		myLocationOverlay.enableMyLocation();
		//got the user required location
		//mapView.getController().animateTo(new GeoPoint((int)latitude*1000000,(int)longitude*1000000));
	}


	@Override
	protected void onStop() {
		
		// TODO Auto-generated method stub
		super.onStop();
		myLocationOverlay.disableMyLocation(); //stop getting updates
	}

	@Override
	protected boolean isRouteDisplayed() {
		// TODO Auto-generated method stub
		return false;
	}
	
	/**
	 * Retrieves the geopoint (lat,long) corresponding to the user's entered address
	 * @param addr
	 * @return
	 */
	public GeoPoint getGeoPoint(String addr){
		//GeoPoint result = new GeoPoint((int)latitude*1000000,(int) longitude*1000000);//current
		GeoPoint result = new GeoPoint(-91,-181);
		
		Geocoder geoCoder = new Geocoder(getBaseContext(),Locale.getDefault());
		 try {
			List<Address> addresses = geoCoder.getFromLocationName(addr, 1);
			if (addresses.size() > 0) 
            {
            	//get all address lines
                for (int i=0; i<addresses.get(0).getMaxAddressLineIndex(); 
                     i++)
                   result = new GeoPoint((int)addresses.get(0).getLatitude()*1000000,
                   (int)addresses.get(0).getLongitude()*1000000);
            }
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			Log.e(TAG, "Address to GeoPoint Problem");
		}
		
		return result;
	}
	
	
	/**
	 * Translates a Geopoint (lat,long) to an address.
	 * @return The address
	 * @author Dalia
	 */
	public String getAddress(){
		 String result="";
		 //get address from location coordinates
		 Geocoder geoCoder = new Geocoder(getBaseContext(),Locale.getDefault());
		 
		 try {
               List<Address> addresses = geoCoder.getFromLocation(
                   latitude, longitude, 1);

               
               if (addresses.size() > 0) 
               {
               	//get all address lines
                   for (int i=0; i<addresses.get(0).getMaxAddressLineIndex(); 
                        i++)
                      result += addresses.get(0).getAddressLine(i) + "\n";
               }

               Toast.makeText(getBaseContext(), result, Toast.LENGTH_SHORT).show();
           }
           catch (IOException e) {  
           	//Toast.makeText(arg1.getContext(),  "exception", Toast.LENGTH_SHORT).show();
           	e.printStackTrace();
           	Log.e(TAG, "Address from Location Problem", e);
           }
           return result;
	}
	
	
	private class MapOverlay extends Overlay {
		
		//used to distinguish between taps and pinches
		private boolean isPinch = false;
		
		/**
		 * @author Dalia
		 * 
		 * Gets the latitude and longitude of the location
		 * that has been tapped by the user on the map.
		 * */
		@Override
		public boolean onTap(GeoPoint arg0, MapView arg1) {
			// TODO Auto-generated method stub
			if (isPinch){
				return false;
			}
			else{
				if ( arg0!=null ) //if we have a geopoint
				{
					longitude = arg0.getLongitudeE6()/1000000.0;
					latitude = arg0.getLatitudeE6()/1000000.0;
					//Toast.makeText(arg1.getContext(),latitude+","+longitude, Toast.LENGTH_SHORT).show();
					
					//get address corresponding to lat,long
					address = getAddress();
		            
					//confirmation dialog
					AlertDialog.Builder builder = new AlertDialog.Builder(arg1.getContext());
					String a = 	getString(R.string.confirm_loc);
					String la = getString(R.string.lat);
					String lo = getString(R.string.longi);
					String msg = "";
					if (Locale.getDefault().getLanguage().equals("ar"))
						msg= a+"\n"+address+"\n"+latitude+la+"\n"+longitude+lo;
					else
						msg= a+"\n"+address+"\n"+la+latitude+"\n"+lo+longitude;
					builder.setMessage(msg)
					.setCancelable(false)
					.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int id) {
							onResult();
						}
					})
					.setNegativeButton(getString(R.string.no), new DialogInterface.OnClickListener() {
						public void onClick(DialogInterface dialog, int id) {
							dialog.cancel();
						}
					});
					AlertDialog alert = builder.create();
					alert.show();
					return super.onTap(arg0, arg1);
				}
				else
				{
					Toast.makeText(arg1.getContext(),getString(R.string.none), Toast.LENGTH_SHORT).show();
					return false;        
				}

			}
		}
		/**
		 * @author Dalia
		 * 
		 *Used to distinguish between different kinds of touches
		 *to the screen (a tap vs a pinch using 2 fingers)
		 * **/
		@Override
		public boolean onTouchEvent(MotionEvent e, MapView mapView) {
			// TODO Auto-generated method stub
			//number of fingers used on screen
			 int fingers = e.getPointerCount();
			// touch down, user didn't lift his finger, don't know it's a pinch yet
			 if (e.getAction()==0) 
				 isPinch = false;             
			 // two fingers, a pinch to zoom
			 if (e.getAction()==2 && fingers==2)
				 isPinch = true;
			
					                        
			return super.onTouchEvent(e, mapView);
		}
		
		

	}
}
